#include <windows.h>
#include <math.h>

#define WIDTH 400
#define HEIGHT 125

HWND win = NULL;
DWORD timer = 0;
HDC specdc = 0, hdc = 0;
HBITMAP bmp = 0;
BYTE *pixels;
HPEN hPen;
unsigned int mode = 0, time = 0, pos = 0, v0, v1 = HEIGHT, grid = 0, a, b;

int sine_rand()
{
    static unsigned int values[10] = {0}, avg = 0;;
    int rn = (rand()%HEIGHT/2+sin(++time/31.416)*HEIGHT/2+HEIGHT/4);
	int index = time % 10;
    if (rn >= HEIGHT) rn = HEIGHT-1;
    else if (rn < 0) rn = 0;
    avg += rn - values[index];
    values[index] = rn;
    return avg / 10;
}

void CALLBACK Update(UINT id, UINT m, DWORD u , DWORD v, DWORD w)
{
    v0 = HEIGHT - 1 - sine_rand();

    if (mode == 0)
    {
        for (a = pos+1; a < HEIGHT * WIDTH; a += WIDTH)
            pixels[a] = 0, pixels[a+1] = 1;

        MoveToEx(specdc, pos, v1, NULL);
		LineTo(specdc, ++pos, v0);

        pos %= WIDTH;
    }
    else if (mode == 1)
    {
		BitBlt(specdc, 1, 0, WIDTH - 1, HEIGHT, specdc, 0, 0, SRCCOPY);
		for (a = 0; a < HEIGHT * WIDTH; a += WIDTH)
            pixels[a] = 0;

        MoveToEx(specdc, 1, v1, NULL);
		LineTo(specdc, 0, v0);
    }
    else //if (mode == 2)  windows taskmgr style
    {
        for (a = 0; a < HEIGHT * WIDTH; a += WIDTH)
        {
            memcpy(pixels + a, pixels + a + 1, WIDTH - 1);
            pixels[a + WIDTH - 1] = 0;
        }

        b = (grid++ % 11) ? 12*WIDTH : WIDTH;
		for (a = 0; a < HEIGHT * WIDTH; a += b)
			pixels[a+WIDTH-1] = 2;

        MoveToEx(specdc, WIDTH - 2, v1, NULL);
		LineTo(specdc, WIDTH - 1, v0);
    }
    v1 = v0;
    BitBlt(hdc, 0, 0, WIDTH, HEIGHT, specdc, 0, 0, SRCCOPY);
}

long FAR PASCAL WProc(HWND h, UINT m, WPARAM w, LPARAM l)
{
    switch (m)
    {
    case WM_PAINT:
    {
		RECT r;
        if (!GetUpdateRect(h, &r, 0)) return 0;
		PAINTSTRUCT p;
		HDC dc = BeginPaint(h, &p);
		if (!dc) return 0;
		BitBlt(dc, r.left, r.top, r.right-r.left, r.bottom-r.top,
				specdc, r.left, r.top, SRCCOPY);
		EndPaint(h, &p);
        return 0;
    }
    case WM_LBUTTONUP:
        mode = (mode + 1) % 3;
        memset(pixels, 0, WIDTH*HEIGHT);
        return 0;

    case WM_CREATE:
        win = h;
        hdc = GetDC(win);

        BYTE data[sizeof(BITMAPINFOHEADER) + 4*sizeof(RGBQUAD)] = {0};
        BITMAPINFO* bh = (BITMAPINFO*)data;
        RGBQUAD* pal = (RGBQUAD*)(data + sizeof(*bh));
        *bh = (BITMAPINFO){sizeof(*bh), WIDTH, HEIGHT, 1, 8, BI_RGB, 0,0,0,4,4};

        pal[0] = (RGBQUAD){0,0,0,0};
        pal[1] = (RGBQUAD){255,255,255,0};
        pal[2] = (RGBQUAD){0,100,0,0};
        pal[3] = (RGBQUAD){0,255,0,0};

        bmp = CreateDIBSection(0, bh, DIB_RGB_COLORS, (void**)&pixels, NULL, 0);
        specdc = CreateCompatibleDC(0);
        SelectObject(specdc, bmp);

		hPen = CreatePen(PS_SOLID, 1, RGB(0,255,0));
		SelectObject(specdc, hPen);

        timer = timeSetEvent(50, 20, (LPTIMECALLBACK)&Update, 0, TIME_PERIODIC);
        break;

    case WM_DESTROY:
        ReleaseDC(win, hdc);
        if (timer) timeKillEvent(timer);
        if (specdc) DeleteDC(specdc);
        if (bmp) DeleteObject(bmp);
        if (hPen) DeleteObject(hPen);
        PostQuitMessage(0);
        break;
    }
    return DefWindowProc(h, m, w, l);
}

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev,LPSTR lpCmd, int nCmdShow)
{
    WNDCLASS wc = {0, WProc, 0, 0, hInst, 0, 0, 0, 0, "Spectrum"};

    if (!RegisterClass(&wc) || !CreateWindow("Spectrum","Ejemplo - DavidXL",
            WS_POPUPWINDOW | WS_CAPTION | WS_VISIBLE, 300, 200,
            WIDTH + 2 * GetSystemMetrics(SM_CXDLGFRAME), HEIGHT +
			GetSystemMetrics(SM_CYCAPTION) + 2*GetSystemMetrics(SM_CYDLGFRAME),
            NULL, NULL, hInst, NULL))
    {
        return 0; //Error
    }

    ShowWindow(win, SW_SHOWNORMAL);

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return 0;
}
